/* * Copyright 2015 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package io.atomix.catalyst.buffer; import java.io.File; import java.nio.channels.FileChannel; /** * Direct {@link java.nio.ByteBuffer} based buffer. * * @author <a href="http://github.com/kuujo">Jordan Halterman</a> */ public class MappedBuffer extends ByteBufferBuffer { /** * Allocates a dynamic capacity mapped buffer in {@link java.nio.channels.FileChannel.MapMode#READ_WRITE} mode with an initial capacity * of {@code 16MiB} and a maximum capacity of {@link Integer#MAX_VALUE}. * <p> * The resulting buffer will have a maximum capacity of {@link Integer#MAX_VALUE}. As bytes are written to the buffer * its capacity will double in count each time the current capacity is reached. Memory will be mapped by opening and * expanding the given {@link java.io.File} to the desired {@code capacity} and mapping the file contents into memory via * {@link java.nio.channels.FileChannel#map(java.nio.channels.FileChannel.MapMode, long, long)}. * * @param file The file to map into memory. * @return The mapped buffer. * @throws NullPointerException If {@code file} is {@code null} * * @see #allocate(java.io.File, java.nio.channels.FileChannel.MapMode) * @see #allocate(java.io.File, long) * @see #allocate(java.io.File, java.nio.channels.FileChannel.MapMode, long) * @see #allocate(java.io.File, long, long) * @see #allocate(java.io.File, java.nio.channels.FileChannel.MapMode, long, long) */ public static MappedBuffer allocate(File file) { return allocate(file, FileChannel.MapMode.READ_WRITE, DEFAULT_INITIAL_CAPACITY, Long.MAX_VALUE); } /** * Allocates a dynamic capacity mapped buffer in {@link java.nio.channels.FileChannel.MapMode#READ_WRITE} mode with an initial capacity * of {@code 16MiB} and a maximum capacity of {@link Integer#MAX_VALUE}. * <p> * The resulting buffer will be initialized to a capacity of {@code 4096} and have a maximum capacity of * {@link Integer#MAX_VALUE}. As bytes are written to the buffer its capacity will double in count each time the current * capacity is reached. Memory will be mapped by opening and expanding the given {@link java.io.File} to the desired * {@code capacity} and mapping the file contents into memory via * {@link java.nio.channels.FileChannel#map(java.nio.channels.FileChannel.MapMode, long, long)}. * * @param file The file to map into memory. * @param mode The mode with which to map the file. * @return The mapped buffer. * @throws NullPointerException If {@code file} is {@code null} * * @see #allocate(java.io.File) * @see #allocate(java.io.File, long) * @see #allocate(java.io.File, java.nio.channels.FileChannel.MapMode, long) * @see #allocate(java.io.File, long, long) * @see #allocate(java.io.File, java.nio.channels.FileChannel.MapMode, long, long) */ public static MappedBuffer allocate(File file, FileChannel.MapMode mode) { return allocate(file, mode, DEFAULT_INITIAL_CAPACITY, Long.MAX_VALUE); } /** * Allocates a fixed capacity mapped buffer in {@link java.nio.channels.FileChannel.MapMode#READ_WRITE} mode. * <p> * Memory will be mapped by opening and expanding the given {@link java.io.File} to the desired {@code capacity} and mapping the * file contents into memory via {@link java.nio.channels.FileChannel#map(java.nio.channels.FileChannel.MapMode, long, long)}. * <p> * The resulting buffer will have a capacity of {@code capacity}. The underlying {@link UnsafeMappedBytes} will be * initialized to the next power of {@code 2}. * * @param file The file to map into memory. * @param capacity The fixed capacity of the buffer to allocate (in bytes). * @return The mapped buffer. * @throws NullPointerException If {@code file} is {@code null} * @throws IllegalArgumentException If the {@code capacity} is greater than {@link Integer#MAX_VALUE}. * * @see #allocate(java.io.File) * @see #allocate(java.io.File, java.nio.channels.FileChannel.MapMode) * @see #allocate(java.io.File, java.nio.channels.FileChannel.MapMode, long) * @see #allocate(java.io.File, long, long) * @see #allocate(java.io.File, java.nio.channels.FileChannel.MapMode, long, long) */ public static MappedBuffer allocate(File file, long capacity) { return allocate(file, FileChannel.MapMode.READ_WRITE, capacity, capacity); } /** * Allocates a fixed capacity mapped buffer in the given {@link java.nio.channels.FileChannel.MapMode}. * <p> * Memory will be mapped by opening and expanding the given {@link java.io.File} to the desired {@code capacity} and mapping the * file contents into memory via {@link java.nio.channels.FileChannel#map(java.nio.channels.FileChannel.MapMode, long, long)}. * <p> * The resulting buffer will have a capacity of {@code capacity}. The underlying {@link UnsafeMappedBytes} will be * initialized to the next power of {@code 2}. * * @param file The file to map into memory. * @param mode The mode with which to map the file. * @param capacity The fixed capacity of the buffer to allocate (in bytes). * @return The mapped buffer. * @throws NullPointerException If {@code file} is {@code null} * @throws IllegalArgumentException If the {@code capacity} is greater than {@link Integer#MAX_VALUE}. * * @see #allocate(java.io.File) * @see #allocate(java.io.File, java.nio.channels.FileChannel.MapMode) * @see #allocate(java.io.File, long) * @see #allocate(java.io.File, long, long) * @see #allocate(java.io.File, java.nio.channels.FileChannel.MapMode, long, long) */ public static MappedBuffer allocate(File file, FileChannel.MapMode mode, long capacity) { return allocate(file, mode, capacity, capacity); } /** * Allocates a mapped buffer. * <p> * Memory will be mapped by opening and expanding the given {@link java.io.File} to the desired {@code count} and mapping the * file contents into memory via {@link java.nio.channels.FileChannel#map(java.nio.channels.FileChannel.MapMode, long, long)}. * <p> * The resulting buffer will have a capacity of {@code initialCapacity}. The underlying {@link UnsafeMappedBytes} will be * initialized to the next power of {@code 2}. As bytes are written to the buffer, the buffer's capacity will double * as long as {@code maxCapacity > capacity}. * * @param file The file to map into memory. If the file doesn't exist it will be automatically created. * @param initialCapacity The initial capacity of the buffer. * @param maxCapacity The maximum capacity of the buffer. * @return The mapped buffer. * @throws NullPointerException If {@code file} is {@code null} * @throws IllegalArgumentException If the {@code capacity} or {@code maxCapacity} is greater than * {@link Integer#MAX_VALUE}. * * @see #allocate(java.io.File) * @see #allocate(java.io.File, java.nio.channels.FileChannel.MapMode) * @see #allocate(java.io.File, long) * @see #allocate(java.io.File, java.nio.channels.FileChannel.MapMode, long) * @see #allocate(java.io.File, java.nio.channels.FileChannel.MapMode, long, long) */ public static MappedBuffer allocate(File file, long initialCapacity, long maxCapacity) { return allocate(file, FileChannel.MapMode.READ_WRITE, initialCapacity, maxCapacity); } /** * Allocates a mapped buffer. * <p> * Memory will be mapped by opening and expanding the given {@link java.io.File} to the desired {@code count} and mapping the * file contents into memory via {@link java.nio.channels.FileChannel#map(java.nio.channels.FileChannel.MapMode, long, long)}. * <p> * The resulting buffer will have a capacity of {@code initialCapacity}. The underlying {@link UnsafeMappedBytes} will be * initialized to the next power of {@code 2}. As bytes are written to the buffer, the buffer's capacity will double * as long as {@code maxCapacity > capacity}. * * @param file The file to map into memory. If the file doesn't exist it will be automatically created. * @param mode The mode with which to map the file. * @param initialCapacity The initial capacity of the buffer. * @param maxCapacity The maximum capacity of the buffer. * @return The mapped buffer. * @throws NullPointerException If {@code file} is {@code null} * @throws IllegalArgumentException If the {@code capacity} or {@code maxCapacity} is greater than * {@link Integer#MAX_VALUE}. * * @see #allocate(java.io.File) * @see #allocate(java.io.File, java.nio.channels.FileChannel.MapMode) * @see #allocate(java.io.File, long) * @see #allocate(java.io.File, java.nio.channels.FileChannel.MapMode, long) * @see #allocate(java.io.File, long, long) */ public static MappedBuffer allocate(File file, FileChannel.MapMode mode, long initialCapacity, long maxCapacity) { if (file == null) throw new NullPointerException("file cannot be null"); if (mode == null) mode = FileChannel.MapMode.READ_WRITE; if (initialCapacity > maxCapacity) throw new IllegalArgumentException("initial capacity cannot be greater than maximum capacity"); if (initialCapacity > Integer.MAX_VALUE) throw new IllegalArgumentException("initial capacity for MappedBuffer cannot be greater than " + Integer.MAX_VALUE); if (maxCapacity > Integer.MAX_VALUE) throw new IllegalArgumentException("maximum capacity for MappedBuffer cannot be greater than " + Integer.MAX_VALUE); return new MappedBuffer(MappedBytes.allocate(file, initialCapacity), 0, initialCapacity, maxCapacity); } protected MappedBuffer(MappedBytes bytes, long offset, long initialCapacity, long maxCapacity) { super(bytes, offset, initialCapacity, maxCapacity, null); } /** * Deletes the underlying file. */ public void delete() { ((MappedBytes) bytes).delete(); } }